package com.ling.module1sbbyyds.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ling.sbbyyds.entity.community.ImagesMd5;

import com.ling.sbbyyds.mapper.community.ImageMd5Mapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.tika.Tika;
import org.apache.tika.metadata.HttpHeaders;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaMetadataKeys;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.xml.sax.helpers.DefaultHandler;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 服务器本地文件上传
 *
 * @author ling
 */
@Component
@Slf4j
public class FileLocalStorageTool {
    /**
     * 当前上传文件路径
     */
    private String currFolderPath;
    /**
     * 当前文件范文前缀
     */
    private String currMediaFilePath;

    /**
     * 图片存储文件夹地址
     */
    @Value("${application.config.fileStoragePath.images}")
    private String imagesFolderPath;
    /**
     * 视频存储文件夹地址
     */
    @Value("${application.config.fileStoragePath.video}")
    private String videosFolderPath;
    /**
     * 音频存储文件夹地址
     */
    @Value("${application.config.fileStoragePath.audio}")
    private String audiosFolderPath;
    /**
     * 文件存储文件夹地址
     */
    @Value("${application.config.fileStoragePath.file}")
    private String filesFolderPath;
    /**
     * 图片文件范文前缀
     */
    @Value("${application.config.mediaFilePath.imageType}")
    private String imageMediaFilePath;
    /**
     * 视频文件范文前缀
     */
    @Value("${application.config.mediaFilePath.videoType}")
    private String videoMediaFilePath;
    /**
     * 音频文件范文前缀
     */
    @Value("${application.config.mediaFilePath.audioType}")
    private String audioMediaFilePath;
    /**
     * 文件范文前缀
     */
    @Value("${application.config.mediaFilePath.fileType}")
    private String fileMediaFilePath;

    @Autowired
    private ImageMd5Mapper imageMd5Mapper;

    /**
     * 保存 图片/文件 到本地
     * 返回文件的访问路径
     *
     * @param folderName 文件夹地址
     * @param fileName   图片名
     * @param bytes      图片字节数据
     * @return 文件访问地址
     */
    public String putImage(String folderName, String fileName, byte[] bytes) {
        // 获取文件后缀类型
        String type = fileName.substring(fileName.lastIndexOf("."));
        //文件转md5码 , 可确保文件重复文件不上传
        String fileMd5 = DigestUtils.md5Hex(bytes);
        // 创建文件实例
        FileUtil.writeBytes(bytes, currFolderPath + folderName + File.separator + fileMd5 + type);
        // 返回访问地址
        return currMediaFilePath + folderName + File.separator + fileMd5 + type;
    }

    /**
     * 上传图片，并查看图片在服务器存储其中是否存在
     * 存在则直接返回地址
     * 不存在则存储图片进服务器并把图片记录在数据库
     *
     * @param folderName      文件夹名称
     * @param file
     * @param uploadType 上传类型 1.图片  2.视频  3.音频  4.其他文件
     */
    public String uploadImage(String folderName, int uploadType, MultipartFile file) throws IOException {
        //选择目录
        boolean b = selUploadType(uploadType);
        if(!b){
            log.error("上传文件类型错误");
        }

        byte[] bytes = IoUtil.readBytes(file.getInputStream());
        // 文件数据转遍MD5在数据库查找
        String fileMd5 = DigestUtils.md5Hex(bytes);
        String filePath = this.fileIsExist(fileMd5);
        if (ObjectUtils.isEmpty(filePath)) {
            // 保存图片到本地
            filePath = this.putImage(folderName, file.getOriginalFilename(), bytes);
            this.saveImagePath(fileMd5, filePath);
        }
        return filePath;
    }

    public String uploadBase64Image(String folderName, String base64) throws IOException {
        String partSeparator = ",";
        if (base64 == null) {
            return null;
        }
        byte[] imgByte;
        if (base64.contains(partSeparator)) {
            base64 = base64.split(partSeparator)[1];
            imgByte = Base64.getMimeDecoder().decode(base64.getBytes(StandardCharsets.UTF_8));
        } else {
            imgByte = Base64.getDecoder().decode(base64);
        }

        String fileMd5 = DigestUtils.md5Hex(imgByte);

        String filePath = this.fileIsExist(fileMd5);
        if (ObjectUtils.isEmpty(filePath)) {
            String fileName = fileMd5 + ".png";
            filePath = this.putImage(folderName, fileName, imgByte);
            this.saveImagePath(fileMd5, filePath);
        }
        return filePath;
    }


    private String fileIsExist(String fileMd5) {
        QueryWrapper<ImagesMd5> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("image_md5", fileMd5);
        ImagesMd5 imagesMd5 = imageMd5Mapper.selectOne(objectQueryWrapper);
        if (Objects.isNull(imagesMd5)) {
            return null;
        }
        return imagesMd5.getFolderName();
    }

    private void saveImagePath(String fileMd5, String filePath) {
        // 将图片存进服务存储器，并添加数据库文件md5数据
        ImagesMd5 imagesMd5 = new ImagesMd5()
                .setImageMd5(fileMd5)
                .setFolderName(filePath);
        imageMd5Mapper.insert(imagesMd5);
    }

    /**
     * 判断上传类型
     * @param uploadType 上传类型 1.图片  2.视频  3.音频  4.其他文件
     */
    private boolean selUploadType(int uploadType){
        switch (uploadType){
            case 1:
                currFolderPath = imagesFolderPath;
                currMediaFilePath = imageMediaFilePath;
                break;
            case 2:
                currFolderPath = videosFolderPath;
                currMediaFilePath = videoMediaFilePath;
                break;
            case 3:
                currFolderPath = audiosFolderPath;
                currMediaFilePath = audioMediaFilePath;
                break;
            case 4:
                currFolderPath = filesFolderPath;
                currMediaFilePath = fileMediaFilePath;
                break;
        }
        return true;
    }


    /**
     * 获取类型
     * @param file
     * @return
     */
    public static String getMimeType(MultipartFile file) {
        AutoDetectParser parser = new AutoDetectParser();
        parser.setParsers(new HashMap<MediaType, Parser>());
        Metadata metadata = new Metadata();
        metadata.add(TikaMetadataKeys.RESOURCE_NAME_KEY, file.getName());
        try (InputStream stream = file.getInputStream()) {
            parser.parse(stream, new DefaultHandler(), metadata, new ParseContext());
        }catch (Exception e){
            throw new RuntimeException();
        }
        log.info("上传文件类型：{}", metadata.get(HttpHeaders.CONTENT_TYPE));
        return metadata.get(HttpHeaders.CONTENT_TYPE);
    }

    /**
     * 判断是否是图片
     * @param file
     * @return
     */
    public static boolean isImage(MultipartFile file){
        String type = getMimeType(file);
        Pattern pattern = Pattern.compile(FileType.FILE_TYPE_IMAGE);
        Matcher m = pattern.matcher(type);
        return m.matches();
    }

    /**
     * 判断是否是视频文件
     * @param file
     * @return
     */
    public static boolean isVideo(MultipartFile file){
        try{
        Tika tika = new Tika();
        String mimeType = tika.detect(file.getBytes());
        return mimeType.startsWith("video/");
        }catch (Exception e) {
            return false;
        }
    }

    /**
     * 判断是否是音频文件
     * @param file
     * @return
     */
    public static boolean isAudio(MultipartFile file){
        String type = getMimeType(file);
        Pattern pattern = Pattern.compile(FileType.FILE_TYPE_AUDIO);
        Matcher m = pattern.matcher(type);
        return m.matches();
    }

    public static class FileType {
        public static final String FILE_TYPE_XLS = "application/vnd.ms-excel";
        public static final String FILE_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        public static final String FILE_TYPE_DOC = "application/msword";
        public static final String FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        public static final String FILE_TYPE_PDF = "application/pdf";
        public static final String FILE_TYPE_JSON = "application/json";
        public static final String FILE_TYPE_XML = "application/xml";
        public static final String FILE_TYPE_PNG = "image/png";
        public static final String FILE_TYPE_SVG = "image/svg";
        public static final String FILE_TYPE_IMAGE = "image/.*";
        public static final String FILE_TYPE_VIDEO = "video/.*";
        public static final String FILE_TYPE_AUDIO = "audio/.*";


    }



}
